package com.zoe.tree.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zoe.tree.entity.SysDept;
import com.zoe.tree.entity.SysDeptRelation;
import com.zoe.tree.mapper.SysDeptMapper;
import com.zoe.tree.service.SysDeptRelationService;
import com.zoe.tree.service.SysDeptService;
import com.zoe.tree.util.SortTreeBuild;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author zbg
 * @date 2023/06/20
 * @description $description
 */
@Service
@RequiredArgsConstructor
public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept> implements SysDeptService {
    private final SysDeptRelationService sysDeptRelationService;

    /**
     * 添加信息部门
     * @param dept 部门
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveDept(SysDept dept) {
        Integer maxSort = baseMapper.getMaxSort(dept.getParentId());
        dept.setSort(maxSort + 1);

        this.save(dept);
        sysDeptRelationService.saveDeptRelation(dept);
        return Boolean.TRUE;
    }

    /**
     * 删除部门
     * @param id 部门 ID
     * @return 成功、失败
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeDeptById(Long id) {
        // 级联删除部门
        LambdaQueryWrapper<SysDeptRelation> queryWrapper = Wrappers.lambdaQuery(SysDeptRelation.class)
                                                                   .eq(SysDeptRelation::getAncestor, id);

        List<Long> idList = sysDeptRelationService.list(queryWrapper)
                                                  .stream()
                                                  .map(SysDeptRelation::getDescendant)
                                                  .collect(Collectors.toList());

        if (CollUtil.isNotEmpty(idList)) {
            for (Long deptId : idList) {
                SysDept sysDept = getById(deptId);
                baseMapper.downSort(sysDept.getParentId(), sysDept.getSort());
            }
            this.removeByIds(idList);
        }

        // 删除部门级联关系
        sysDeptRelationService.removeDeptRelationById(id);
        return Boolean.TRUE;
    }

    /**
     * 更新部门
     * @param sysDept 部门信息
     * @return 成功、失败
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateDeptById(SysDept sysDept) {
        // 更新部门状态
        this.updateById(sysDept);
        // 更新部门关系
        SysDeptRelation relation = new SysDeptRelation();
        relation.setAncestor(sysDept.getParentId());
        relation.setDescendant(sysDept.getDeptId());
        sysDeptRelationService.updateDeptRelation(relation);
        return Boolean.TRUE;
    }

    @Override
    public List<Long> listChildDeptId(Long deptId) {
        List<SysDeptRelation> deptRelations = sysDeptRelationService.list(Wrappers.<SysDeptRelation>lambdaQuery()
                                                                                  .eq(SysDeptRelation::getAncestor, deptId)
                                                                                  .ne(SysDeptRelation::getDescendant, deptId));
        if (CollUtil.isNotEmpty(deptRelations)) {
            return deptRelations.stream().map(SysDeptRelation::getDescendant).collect(Collectors.toList());
        }
        return new ArrayList<>();
    }

    @Override
    public Set<SysDept> listDeptTrees() {
        QueryWrapper<SysDept> queryWrapper = Wrappers.emptyWrapper();

        List<SysDept> sysDepts = baseMapper.selectList(queryWrapper);
        return SortTreeBuild.<SysDept, Long>builder()
                            .collection(sysDepts)
                            .nodeId(SysDept::getDeptId)
                            .pidId(SysDept::getParentId)
                            .setChildren(SysDept::addChildren)
                            .build();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean move(SysDept newDept) {

        SysDept oldDept = baseMapper.selectById(newDept.getDeptId());

        Long nextId = newDept.getNextId();
        if (ObjectUtil.notEqual(newDept.getParentId(), oldDept.getParentId())) { // 如果非同层节点移动

            Integer oldSort = oldDept.getSort();
            Long oldPid = oldDept.getParentId();

            // 如果next节点为空,那么默认放到新pid的最后面的位置,移出位置node的后面元素全部-1
            if (ObjectUtil.isNull(nextId)) {
                Integer maxSort = baseMapper.getMaxSort(newDept.getParentId());
                newDept.setSort(maxSort + 1);
                baseMapper.downSort(oldPid, oldSort);
            }
            else {
                // 非同级，需要切换父节点，原父节点移出位置的后面的元素往前移动一位+1，新父节点移入位置以及的后面的元素往后移动一位
                SysDept nextDept = getById(newDept.getNextId());
                Integer newSort = nextDept.getSort();
                newDept.setSort(newSort);
                baseMapper.upperSort(newDept.getParentId(), newSort); // 新父级子节点sort+1
                baseMapper.downSort(oldPid, oldSort); // 旧父级子节点sort-1
            }
        }
        else { // 同级修改
            if (ObjectUtil.isNull(nextId)) {
                Integer maxSort = baseMapper.getMaxSort(newDept.getParentId());
                newDept.setSort(maxSort);
                Integer oldSort = oldDept.getSort();
                baseMapper.peerDownSort(newDept.getParentId(), maxSort, oldSort);
            }
            else {
                SysDept nextDept = getById(newDept.getNextId());
                Integer newSort = nextDept.getSort();
                Integer oldSort = oldDept.getSort();
                if (oldSort > newSort) { // 如果原来的sort比next的sort大;说明我现在是要放在next节点的前面
                    newDept.setSort(newSort);
                    baseMapper.peerUpperSort(newDept.getParentId(), newSort, oldSort);
                }
                else {
                    int newSortDecrement = newSort - 1;
                    newDept.setSort(newSortDecrement);
                    baseMapper.peerDownSort(newDept.getParentId(), newSortDecrement, oldSort);
                }
            }
        }
        return updateDeptById(newDept);
    }
}
